/*
 * N900DataInfo.cpp
 *
 *  Created on: Aug 19, 2016
 *      Author: ubuntu
 */

#include "N900DataInfo.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/un.h>
#include <arpa/inet.h>
#include <netdb.h>

#include "../Conf.h"

using namespace std;

N900DataInfo::N900DataInfo() : DataInfo()
{
	memset(&m_msg, 0, sizeof(m_msg));
	m_msg.curtime = time(NULL);
	m_pbuf = NULL;
	m_len = 0;
}

N900DataInfo::~N900DataInfo()
{
	switch (m_msg.type) {
	case N900_CARDATA:
		{
			if (m_msg.m_sec)
				free(m_msg.m_sec);
			if (m_msg.m_drive)
				free(m_msg.m_drive);
		}
		break;
	case N900_GPSDATA:
		if (m_msg.m_gps)
			free(m_msg.m_gps);
		break;
	case N900_REPORT:
		if (m_msg.m_type != N900_RP_FAULT) {
			break;
		}
		if (m_msg.m_fault)
			free(m_msg.m_fault);
		break;
	case N900_BEATDATA:
		if (m_msg.m_type == N900_BT_RESPOND) {
			switch (m_msg.m_cmdType) {
			case 0x01:
				if (m_msg.m_fault)
					free(m_msg.m_fault);
				break;
			case 0xF1:
				if (m_msg.m_log)
					free(m_msg.m_log);
				break;
			default:
				break;
			}
		}
		break;
	}
	if (m_pbuf)
		free(m_pbuf);
}

bool N900DataInfo::parse(unsigned char *pBuf, size_t len, int add_head, int add_tail)
{
	unsigned char *buf = pBuf + add_head;
	m_pbuf = pBuf;
	m_len = len;
	m_head = add_head;
	m_tail = add_tail;
	if (n900_parse_package(buf, len, &m_msg) < 0)
		return false;
	return true;
}

void N900DataInfo::debugInfo()
{
	switch (m_msg.type) {
	case N900_CARDATA:
		{
			break;
			if (m_msg.result == false) {
				debug(LOG_ERR, "不正常啊");
				break;
			}
			char *dbuf = (char *)malloc(MAX_MALLOC_SIZE);
			int n = 0;
			if (dbuf && m_msg.m_sec) {
				for (int i = 0; i < m_msg.m_sectionDataCount; i++) {
					n += snprintf(dbuf+n, MAX_MALLOC_SIZE-n, "%s ", parseSection(m_msg.m_sec[i].id).c_str());
					n += snprintf(dbuf+n, MAX_MALLOC_SIZE-n, " 行驶%d秒 %.3f公里; 油耗: %.3f升\n", m_msg.m_sec[i].stime, m_msg.m_sec[i].mileage, m_msg.m_sec[i].fuelConsumption);
				}
			}
			if (dbuf && m_msg.m_drive) {
				for (int i = 0; i < m_msg.m_driveActionCount; i++) {
					n += snprintf(dbuf+n, MAX_MALLOC_SIZE-n, "%s %d次", parseDriveActive(m_msg.m_drive[i].id).c_str(), m_msg.m_drive[i].count);
					vector<time_t>::iterator it = m_msg.m_drive[i].dtime.begin();
					for (; it != m_msg.m_drive[i].dtime.end(); it++) {
						n += snprintf(dbuf+n, MAX_MALLOC_SIZE-n, " %s", dateftime((*it), "%F %H:%M:%S").c_str());
					}
					n += snprintf(dbuf+n, MAX_MALLOC_SIZE-n, "\n");
				}
			}
			debug(LOG_DEBUG, "\n时间: %s\n"
					"平均速度: %d 公里/小时\n"
					"最大速度: %d 公里/小时\n"
					"最小速度: %d 公里/小时\n"
					"累计油耗: %.3f 升\n"
					"累计里程: %.3f 公里\n"
					"%s", 
					dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(),
					m_msg.m_avgSpeed, m_msg.m_maxSpeed, m_msg.m_minSpeed, m_msg.m_fuleConsumptionTotal,
					m_msg.m_mileageTotal,
					dbuf ? dbuf : "");
			if (dbuf)
				free(dbuf);
		}
		break;
	case N900_GPSDATA:
		{
			break;
			if (m_msg.result == false) {
				debug(LOG_ERR, "不正常啊");
				break;
			}
			char *dbuf = (char *)malloc(m_msg.m_gpscnt * MIN_MALLOC_SIZE/2);
			int n = 0;
			if (dbuf) {
				n += sprintf(dbuf, "GPS数据传输消息: \n");
				for (int i = 0; i < m_msg.m_gpscnt; i++) {
					n += sprintf(dbuf+n, "%s %s %.5f %s %.5f\n",
							dateftime(m_msg.m_gps[i].m_time, "%F %H:%M:%S").c_str(),
							(m_msg.m_gps[i].m_latDir == 'N') ? "北纬" : "南纬",
							m_msg.m_gps[i].m_lat,
							(m_msg.m_gps[i].m_lngDir == 'E') ? "东经" : "西经",
							m_msg.m_gps[i].m_lng);
				}
				debug(LOG_DEBUG, "%s", dbuf);
				free(dbuf);
			}
		}
		break;
	case N900_BEATDATA:
		{
			if (m_msg.result == false) {
				debug(LOG_ERR, "不正常啊");
				break;
			}
			switch (m_msg.m_type) {
			case N900_BT_TIME:
				debug(LOG_DEBUG, "时间同步");
				break;
			case N900_BT_CMD:
				{
					debug(LOG_DEBUG, "命令申请, 当前系统版本: %d", m_msg.m_version);
				}
				break;
			case N900_BT_RESPOND:
				{
					char *buf = (char *)malloc(MIN_MALLOC_SIZE);
					if (!buf) {
						debug(LOG_DEBUG, "命令响应");
						break;
					}
					int n = 0;

					n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "命令响应:\n");
					switch (m_msg.m_cmdType) {
					case 0x00:
						n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "无命令类型");
						break;
					case 0x01:
						{
							n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "车辆体检状态\n");
							if (m_msg.m_faultCnt > 0 && m_msg.m_fault) {
								for (size_t k = 0; k < m_msg.m_faultCnt; k++)
								{
									char mark;
									int flag = m_msg.m_fault[k].id & 0x3FFF;
									const char *status = m_msg.m_fault[k].status == 0 ? "当前" : (m_msg.m_fault[k].status == 1 ? "偶发" : "未决");
									switch ((m_msg.m_fault[k].id & 0xC0) >> 14) {
									case 0x00:
										mark = 'P';
										break;
									case 0x01:
										mark = 'C';
										break;
									case 0x02:
										mark = 'B';
										break;
									case 0x03:
										mark = 'U';
										break;
									}
									n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "故障: %C%04X, 状态: %s\n", mark, flag, status);
								}
							}
							n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "发动机转速: %d\n"
									"开环或闭环状态: %s\n"
									"车速: %d\n"
									"目标空燃比: %.1f\n"
									"节气门开度: %d\n"
									"发动机温度: %d\n"
									"进气温度: %d\n"
									"大气压力: %d\n"
									"进气压力: %d\n"
									"空气流量: %.2f\n"
									"控制模块电压: %.1f\n"
									"点火提前角: %d\n",
									m_msg.m_engineSpeed,
									(m_msg.m_loop_flag == 0) ? "开环" : (m_msg.m_loop_flag == 1 ? "闭环" : "不支持"),
									m_msg.m_carspeed,
									m_msg.m_airfuelRatio,
									m_msg.m_throttleOpen,
									m_msg.m_engineTemp,
									m_msg.m_inletTemp,
									m_msg.m_atomosPress,
									m_msg.m_inletPress,
									m_msg.m_airFlow,
									m_msg.m_ctlModeVol,
									m_msg.m_ignitionAngle );
						}
						break;
					case 0x02:
						n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "清除故障码 %s", m_msg.m_clearStatus ? "清除成功" : "清除失败");
						break;
					case 0x03:
						n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "参数设定 %s",
								m_msg.m_paramSetup ? "成功" : "失败");
						break;
					case 0x04:
						n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "软件升级 软件版本: %d.%d", 
								(m_msg.m_version >> 8) & 0xFF, m_msg.m_version & 0xFF);
						break;
					case 0x80:
						break;
					case 0xF1:
						{
							n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "日志 %d: %s", m_msg.m_logtype, m_msg.m_log ? m_msg.m_log : "内存分配失败");
						}
						break;
					default:
						n += snprintf(buf+n, MIN_MALLOC_SIZE-n, "错误类型: %02X", m_msg.m_cmdType);
						break;
					}
					debug(LOG_DEBUG, "%s", buf);
					free(buf);
				}
				break;
			case N900_BT_AGPS:
				debug(LOG_DEBUG, "AGPS请求: id: %u, 纬度: %.5f, 经度: %.5f, 索引: %u", 
						m_msg.m_agpsId, m_msg.m_agpsLat * 0.00001, m_msg.m_agpsLon * 0.00001, m_msg.m_index);
				break;
			}
		}
		break;
	case N900_REPORT:
		{
			break;
			if (m_msg.result == false) {
				debug(LOG_ERR, "不正常啊");
				return;
			}
			switch (m_msg.m_type) {
			case N900_RP_FAULT:
				debug(LOG_DEBUG, "%s 着车故障上报", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str());
				break;
			case N900_RP_STALLED:
				debug(LOG_DEBUG, "%s 熄火", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str());
				break;
			case N900_RP_LOWVOL:
				debug(LOG_DEBUG, "%s 电压: %.1f V", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(), m_msg.m_voltage);
				break;
			case N900_RP_SHOCK:
				debug(LOG_DEBUG, "%s 熄火震动", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str());
				break;
			case N900_RP_ONPOW:
				if (m_msg.m_offtime > 0) {
					debug(LOG_DEBUG, "%s 上电; %s 断电", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(), dateftime(m_msg.m_offtime, "%F %H:%M:%S").c_str());
				} else {
					debug(LOG_DEBUG, "%s 上电", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str());
				}
				break;
			case N900_RP_VINCODE:
				if (m_msg.m_marktype == 0) {
					debug(LOG_DEBUG, "%s 读取VIN协议: %d, 识别码: %s", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(), m_msg.m_protype, m_msg.m_vinCode);
				} else {
					debug(LOG_DEBUG, "%s 读取发动机编号 协议: %d, 识别码: %s", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(), m_msg.m_protype, m_msg.m_vinCode);
				}
				break;
			case N900_RP_IMSICODE:
				debug(LOG_DEBUG, "%s 读取ISMI号: %s", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(), m_msg.m_ismiCode);
				break;
			case N900_RP_STATUS:
				debug(LOG_DEBUG, "%s 设备状态: %d, 电压: %.1f V", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(), 
						m_msg.m_status, m_msg.m_voltage);
				break;
			case N900_RP_EXCEPTN:
				debug(LOG_DEBUG, "%s 设备故障: %d", dateftime(m_msg.msg_time, "%F %H:%M:%S").c_str(), m_msg.m_exptype);
				break;
			}
		}
		break;
	case N900_FILETRANS:
//		debug(LOG_DEBUG, "N900 文件传输: 文件名: %s, 数据帧: %d", m_msg.m_file, m_msg.m_sequence);
		break;
	}
}

string N900DataInfo::parseSection(int id)
{
	string standard = "";
	switch(id) {
	case 0x00:
		standard = "0-20 公里/小时";
		break;
	case 0x01:
		standard = "20-40 公里/小时";
		break;
	case 0x02:
		standard = "40-60 公里/小时";
		break;
	case 0x03:
		standard = "60-80 公里/小时";
		break;
	case 0x04:
		standard = "80-100 公里/小时";
		break;
	case 0x05:
		standard = "100-120 公里/小时";
		break;
	case 0x06:
		standard = "120-140 公里/小时";
		break;
	case 0x07:
		standard = "140-160 公里/小时";
		break;
	case 0x08:
		standard = "高于160 公里/小时";
		break;
	default:
		standard = "错误分段数据";
		break;
	}
	return standard;
}

string N900DataInfo::parseDriveActive(int id)
{
	string desc = "";
	switch (id) {
	case 0x0A:
		desc = "急加速";
		break;
	case 0x0B:
		desc = "急减速";
		break;
	case 0x0C:
		desc = "急转弯";
		break;
	case 0x0D:
		desc = "高转速";
		break;
	case 0x0E:
		desc = "车速与转速不匹配";
		break;
	default:
		desc = "瞎说";
		break;
	}
	return desc;
}

int N900DataInfo::sendBuf(unsigned char *dst, const unsigned char *buf, size_t len, N900DevStatus *pStatus)
{
	size_t k = 0;
	size_t nlen = 0;
	size_t pos;
	memcpy(dst, buf, 11);
	k += 11;
	pos = k;
	k += 2;
	switch (m_msg.type) {
	case N900_CARDATA:
		{
			nlen = 1;
			if (m_msg.result) {
				dst[k++] = 0;
			} else {
				dst[k++] = 1;
			}
			if (pStatus) {
				pStatus->setTime(m_msg.msg_time, N900_CAR_TIME);
				pStatus->setSpeed(m_msg.m_avgSpeed);
			}
		}
		break;
	case N900_BEATDATA:
		{
			switch (m_msg.m_type) {
			case N900_BT_TIME:
				{
					nlen = 4;
					time_t ts = time(NULL);
					dst[k++] = (ts >> 24 ) & 0xFF;
					dst[k++] = (ts >> 16 ) & 0xFF;
					dst[k++] = (ts >> 8 ) & 0xFF;
					dst[k++] = ts & 0xFF;
				}
				break;
			case N900_BT_CMD:
				{
					if (m_msg.result == false) {
						nlen = 1;
						dst[k++] = 0;
						debug(LOG_DEBUG, "解析错误");
						break;
					}
					if (!pStatus) {
						nlen = 1;
						dst[k++] = 0;
						break;
					}
					if (pStatus->getMaxTime() == 0) {
						nlen = 1;
						dst[k++] = 0;
						break;
					}
					if (m_msg.curtime - pStatus->getMaxTime() < 10) {
						time_t ts = m_msg.curtime;
						if (m_msg.m_version < get_n900_version() && get_n900_file() && pStatus) {
							struct stat buf;
							int fcount = 0;
							char *file = get_n900_file();
							if (pStatus->isUpdate() && stat(file, &buf) == 0) {
								nlen = 1;
								fcount = buf.st_size / 512 + 1;
								dst[k++] = 4;
								memcpy(&dst[k], file, strlen(file));
								k += 32;
								nlen += 36;
								dst[k++] = 0;
								dst[k++] = 0;
								dst[k++] = 0;
								dst[k++] = 0;
								dst[k++] = (fcount >> 8) & 0xFF;
								dst[k++] = fcount & 0xFF;
								nlen += 2;
								break;
							}
						}

						if ((ts - pStatus->getCarTime() <= 30) && pStatus->getSpeed() < 120 &&
								(ts - pStatus->getCheckTime() >= 180)) {
							nlen = 1;
							dst[k++] = 1;
							pStatus->setTime(ts, N900_CHECK_TIME);
							break;
						} else {
							nlen = 1;
							dst[k++] = 0;
							break;
						}
					} else {
						nlen = 1;
						dst[k++] = 0;
					}
				}
				break;
			case N900_BT_RESPOND:
				{
					nlen = 1;
					if (m_msg.result) {
						dst[k++] = 0;
					} else {
						dst[k++] = 1;
					}
				}
				break;
			case N900_BT_AGPS:
				{
					if (m_msg.result) {
						unsigned int newId = m_msg.m_agpsId + 23413;
						unsigned int newIndex = m_msg.m_index + 1;
						dst[k++] = (newId >> 24 ) & 0xFF;
						dst[k++] = (newId >> 16 ) & 0xFF;
						dst[k++] = (newId >> 8 ) & 0xFF;
						dst[k++] = newId & 0xFF;
						nlen = 4;

						dst[k++] = (120 >> 8) & 0xFF;
						dst[k++] = 120 & 0xFF;
						nlen += 2;

						dst[k++] = newIndex & 0xFF;
						nlen++;
						for (size_t j = 0; j < 120; j++) {
							dst[k++] = (j * j + j * 3 ) & 0xFF;
						}
						nlen += 120;
					} else {
						nlen = 1;
						dst[k++] = 1;
					}
				}
				break;
			default:
				nlen = 1;
				dst[k++] = 0xFF;
				break;
			}
		}
		break;
	case N900_GPSDATA:
	case N900_REPORT:
		{
			nlen = 1;
			if (m_msg.result) {
				dst[k++] = 0;
			} else {
				dst[k++] = 1;
			}
		}
		break;
	case N900_FILETRANS:
		{
			int fd = open(m_msg.m_file, O_RDONLY);
			int nread, pis;
			pis = k;
			if (fd < 0) {
				nlen = 1;
				dst[k++] = 0xFF;
				break;
			}
			lseek(fd, m_msg.m_sequence * 512, SEEK_SET);
			debug(LOG_DEBUG, "文件: %s, 数据帧: %u", m_msg.m_file, m_msg.m_sequence);
			nread = read(fd, dst+k+4, 512);
			if (nread < 0)
			{
				nlen = 1;
				dst[pis] = 0xFF;
				k = pis+1;
				break;
			} else {
				nlen = 2;
				dst[k++] = (m_msg.m_sequence >> 8) & 0xFF;
				dst[k++] = m_msg.m_sequence & 0xFF;
				nlen += 2;
				dst[k++] = (nread >> 8) & 0xFF;
				dst[k++] = nread & 0xFF;
				nlen += nread;
				k += nread;
			}
			close(fd);
		}
		break;
	default:
		{
			nlen = 1;
			dst[k++] = 0xFF;
		}
		break;
	}
	if (pStatus)
		pStatus->setTime(m_msg.curtime, N900_MAX_TIME);
	dst[pos] = (nlen >> 8) & 0xFF;
	dst[pos+1] = nlen & 0xFF;
	if (k+N900_TAG_TAIL_LEN > len)
		return -1;
	memcpy(&dst[k], N900_TAG_TAIL, N900_TAG_TAIL_LEN);
	k += N900_TAG_TAIL_LEN;
	return k;
}

unsigned int N900DataInfo::getObdid()
{
	return m_msg.obdid;
}

void N900DataInfo::setObdid(unsigned int obdid)
{
	m_msg.obdid = obdid;
}

void N900DataInfo::writelog(const char *path)
{
	int fd = socket(AF_UNIX, SOCK_STREAM, 0);
	struct sockaddr_un addr;
	int mhlen = 0;
	if (fd < 0)
		goto send_fail;

	bzero(&addr, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);

	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		close(fd);
		goto send_fail;
	}

	mhlen = DM_TAG_HEAD_LEN + 5;
	if (m_head >= mhlen) {
		int n = 0;
		unsigned char *pBuf = m_pbuf + m_head - mhlen;
		memcpy(pBuf, DM_TAG_HEAD, DM_TAG_HEAD_LEN);
		n += DM_TAG_HEAD_LEN;
		pBuf[n++] = SV_N900;
		pBuf[n++] = (m_msg.curtime >> 24) & 0xFF;
		pBuf[n++] = (m_msg.curtime >> 16) & 0xFF;
		pBuf[n++] = (m_msg.curtime >> 8) & 0xFF;
		pBuf[n++] = m_msg.curtime & 0xFF;
		if (write(fd, pBuf, m_len + mhlen) < 0) {
			close(fd);
			goto send_fail;
		}
	} else {
		debug(LOG_DEBUG, "不能这么搞的");
		close(fd);
		goto send_fail;
	}

	close(fd);
	return;
send_fail:
	locallog();
	free(m_pbuf);
	m_pbuf = NULL;
}

void N900DataInfo::locallog()
{
	char file[40];
	unsigned char *pBuf = m_pbuf + m_head;
	struct custime cus = timetocstm(m_msg.curtime);
	snprintf(file, sizeof(file), "log/n900%04d%02d%02d%02d%02d", cus.year, cus.month, cus.day, cus.hour, cus.min);
	FILE *fp = fopen(file, "a+");
	if (!fp)
		return;
	fprintf(fp, "%08X", m_msg.curtime);
	for (size_t i = 0; i < m_len; i++) {
		fprintf(fp, "%02X", pBuf[i]);
	}
	fprintf(fp, "\n");
	fclose(fp);
}
